/* 
 * File:   stackrecord.h
 * Author: tomas
 *
 * Created on March 28, 2009, 4:45 PM
 */

#pragma once
#ifndef _STACKRECORD_H
#define _STACKRECORD_H

#include <vector>
#include <iostream>
#include <cmath>

#include <boost/serialization/access.hpp>
#include <boost/serialization/vector.hpp>

#include "move.h"
#include "Instance.h"
#include "utils.h"


struct StackRecord
{

	friend class boost::serialization::access;

	//Typ drzici konfiguraci herni desky
	typedef utils::Board boardLayout_t;

	//jendotlive bity odpovidaji polickum v desce cteno zleva doprava, po radcich dolu.
	//[0,0] = index 0
	boardLayout_t boardLayout;

	//Historie tahu je ted soucasti stavu
	std::vector<Move> movesHistory;

	//Hloubka v grafu (vzdalenost od korene)
	unsigned depth;

	//Suma penalizaci za tahy od pocatku do tohoto stavu.
	unsigned totalPenalty;

	//////////////////////////////////////////////////////////////////////////
	//Default ctor. pouzivat jen napr. pri deserializaci.
	StackRecord ():
	boardLayout(), depth(0), totalPenalty(0)
	{
	}

	//////////////////////////////////////////////////////////////////////////
	//Ctor pro pocatecni uzel
	StackRecord (const boardLayout_t& _layout):
	boardLayout(_layout), depth(0), totalPenalty(0)
	{
	}

	//////////////////////////////////////////////////////////////////////////
	//Ctor pro ostatni uzly v hloubce >0
	StackRecord (const boardLayout_t& _layout,
			const StackRecord& orig,
			const Move& last,
			const unsigned penalty):
	boardLayout(_layout), depth(orig.depth+1), totalPenalty(orig.totalPenalty+penalty)
	{
		this->movesHistory = orig.movesHistory;
		this->movesHistory.push_back(last);
	}

	bool operator==(const StackRecord& that) const
	{
		if (this->totalPenalty!=that.totalPenalty || this->depth!=that.depth)
		{
			return false;
		}
		if (this->boardLayout != that.boardLayout)
		{
			return false;
		}
		if (this->movesHistory.size()!=that.movesHistory.size())
		{
			return false;
		}
		for (unsigned i = 0; i<that.movesHistory.size(); ++i)
		{
			if (this->movesHistory[i]!=that.movesHistory[i])
			{
				return false;
			}
		}
		return true;
	}

	bool operator!= (const StackRecord& that) const
	{
		return !(*this == that);
	}

	//////////////////////////////////////////////////////////////////////////
	//Vypis zaznamu.
	friend std::ostream& operator<< (std::ostream& os, const StackRecord& sr)
	{
		unsigned wdth = (unsigned) ceil(sqrt((double) sr.boardLayout.size()));
		utils::printVector(os,sr.movesHistory);
		os << "\n";
		os << "depth = " << sr.depth << "\n";
		os << "total penalty = " << sr.totalPenalty << "\n";
		for (unsigned i = 0; i<sr.boardLayout.size(); ++i)
		{
			if (sr.boardLayout[i])
			{
				os << 'X';
			}
			else
			{
				os << '.';
			}
			if ((i+1)%wdth == 0)
			{
				os << '\n';
			}

		}

		return os;
	}

private:
	template<class Archive>
	inline void serialize(Archive& ar, const unsigned int version)
	{
		ar & boardLayout & movesHistory & depth & totalPenalty;
	}
};

#endif	/* _STACKRECORD_H */


